package org.example;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.CharsetUtil;
import org.example.handler.NettyServerHandler;

/**
 * Netty Server
 * <p>
 * NIO 编程（基于事件驱动）
 * <p>
 * NioEventLoop（异步非阻塞）
 * OioEventLoopGroup(同步阻塞）
 * <p>
 * Channel（Stream，双向数据流，与Socket文件进行数据交换），建立Socekt连接后，创建对应的Channel实例并注册到NioEventLoopGroup中
 * > 其之类ServerSocket Socket 基于TCP协议，Datagram基于UDP协议
 * > ChannelHandler/Context  处理Channel I/O 事件或拦截 I/O
 * > > ChannelPipline,将ChannelHandler存入容器中，实现ChannelHandler顺序执行
 * > > >
 * <p>
 * Buffer(缓冲区（容器），能够跟踪缓存区的状态变化）
 * > 其子类基本数据类型缓存区+ByteBuffer
 * <p>
 * Select（注册多个Channel=>通常由一个线程监听有Socket，Socket发送改变，）
 * <p>
 * NIO基于Channel和Buffer进行操作，数据总是从通道读取到缓冲区中，
 * Selector用于监听多个通道的事件（比如连接打开，数据到达）。因此，单个线程可以监听多个数据通道
 * <p>
 * <p>
 * Client创建连接请求，NioEventLoop通过Selector并监听Socket文件读写事件，存在网络IO则使用线程组将该事件注册到Channel任务
 * ChannelEventLoop 处理网络IO请求  ====> Pipeline
 */
public class ServerBootStrap {
    public static void main(String[] args) throws InterruptedException {
        new ServerBootstrap()
                .group(new NioEventLoopGroup(), new NioEventLoopGroup())
                .channel(NioServerSocketChannel.class)
                .handler(new LoggingHandler(LogLevel.INFO))
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        // 基于行的帧解码器，即会按照行分隔符对数据进行拆包粘包 maxLeng  frame 长度
                        //   ch.pipeline().addLast(new LineBasedFrameDecoder(6000));
                        // 基于指定分隔符进行拆包粘包
                        ByteBuf byteBuf = Unpooled.copiedBuffer("D:".getBytes());
                        ch.pipeline().addLast(new DelimiterBasedFrameDecoder(6000, byteBuf));
                        ch.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));
                        ch.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8));
                        ch.pipeline().addLast(new NettyServerHandler());
                    }
                }).bind(9999);
    }

}
